// @HEADER
//*********************************************************************//
//  SiYuan: A numerical PDE solver                                     //
//  Copyright (2022) YUAN Xi                                           //
//  This Software is released under the BSD 2-Clause license detailed  //
//  in the file "LICENSE" in the top-level SiYuan directory            //
//*********************************************************************//
// @HEADER

#ifndef _ROLSOLVER_H
#define _ROLSOLVER_H

#include <iostream>

#include "ROL_ThyraVector.hpp"
#include "ROL_ScaledThyraVector.hpp"
#include "ROL_Thyra_BoundConstraint.hpp"
#include "ROL_ThyraME_Objective.hpp"
#include "ROL_ThyraProductME_Objective.hpp"
#include "Piro_ThyraProductME_Objective_SimOpt.hpp"
#include "Piro_ThyraProductME_Constraint_SimOpt.hpp"
#include "ROL_LineSearchStep.hpp"
#include "ROL_TrustRegionStep.hpp"
#include "ROL_Algorithm.hpp"
#include "ROL_Reduced_Objective_SimOpt.hpp"
#include "ROL_OptimizationSolver.hpp"
#include "ROL_BoundConstraint_SimOpt.hpp"
#include "ROL_Bounds.hpp"
#include "Thyra_VectorDefaultBase.hpp"
#include "Thyra_DefaultProductVectorSpace.hpp"
#include "Thyra_DefaultProductVector.hpp"
#include "Thyra_DefaultBlockedLinearOp.hpp"

namespace SiYuan {


/** \brief Generalized Eigen ModelEvaluator.
 *
 * This class is used to calcualte Eigen values
 */
template<class Scalar>
class ROLSolver : public Thyra::ResponseOnlyModelEvaluatorBase<Scalar>
{
  typedef Thyra::ModelEvaluatorBase MEB;

public:

  /** \name Initializers/Accessors */
  //@{

  /** \brief . */
  ROLSolver( Teuchos::ParameterList& appParams,
    Teuchos::RCP<Thyra::ModelEvaluatorDefaultBase<Scalar> > piroModel,
    Teuchos::RCP< Piro::ROL_ObserverBase<Scalar> > observer = Teuchos::null );

  //@}

  /** \name Public functions overridden from ModelEvaulator. */
  //@{

  /** \brief . */
  Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> > get_p_space(int l) const;
  /** \brief . */
  Teuchos::RCP<const Teuchos::Array<std::string> > get_p_names(int l) const;
  /** \brief . */
  Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> > get_g_space(int j) const;
  /** \brief . */
  Teuchos::ArrayView<const std::string> get_g_names(int j) const;
  /** \brief . */
  Thyra::ModelEvaluatorBase::InArgs<Scalar> createInArgs() const;
  //@}


private: // functions

  /** \name Private functions overridden from ModelEvaulatorDefaultBase. */
  //@{

  /** \brief . */
  Thyra::ModelEvaluatorBase::OutArgs<Scalar> createOutArgsImpl() const;
  /** \brief . */
  void evalModelImpl(
    const Thyra::ModelEvaluatorBase::InArgs<Scalar> &inArgs,
    const Thyra::ModelEvaluatorBase::OutArgs<Scalar> &outArgs
    ) const;

  //@}

private: // data members
  Teuchos::RCP<const Thyra::VectorSpaceBase<Scalar> > x_space_;
  Teuchos::RCP<Thyra::DefaultProductVectorSpace<Scalar>> p_space_;
  
  Teuchos::RCP<Thyra::ModelEvaluatorDefaultBase<Scalar> > model_;
  Teuchos::RCP<Piro::ROL_ObserverBase<Scalar> > observer_;
  int num_p_, num_g_;
  std::vector<int> p_indices_;
  Teuchos::RCP<Thyra::VectorBase<Scalar>> x_;
  Teuchos::RCP< Thyra::VectorBase<Scalar> > result_;
  ROL::Ptr<ROL::Vector<Scalar> > rol_x_ptr_;
  ROL::Ptr<ROL::Vector<Scalar> > rol_p_ptr_;
  ROL::Ptr<ROL::Objective_SimOpt<Scalar> > obj_ptr_;
  ROL::Ptr<ROL::Constraint_SimOpt<Scalar> > constr_ptr_;
  ROL::Ptr<ROL::Algorithm<Scalar> > algo_;
  ROL::Ptr<ROL::Reduced_Objective_SimOpt<Scalar>> reduced_obj_ptr_;
  
  bool boundConstrained, useFullSpace, print_;
  Teuchos::RCP<Teuchos::FancyOStream> out;
  Teuchos::ParameterList rolParams;

};


} // namespace SiYuan

#include "ROLSolver_impl.hpp"

#endif
